/*
* The Unified Mapping Platform (JUMP) is an extensible, interactive GUI for
* visualizing and manipulating spatial features with geometry and attributes.
*
* Copyright (C) 2003 Vivid Solutions
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation; either version 2 of the License, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 59 Temple
* Place - Suite 330, Boston, MA 02111-1307, USA.
*
* For more information, contact:
*
* Vivid Solutions Suite #1A 2328 Government Street Victoria BC V8T 5G5 Canada
*
* (250)385-6040 www.vividsolutions.com
*/
package com.vividsolutions.jump.workbench.ui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Component;
import java.awt.Dialog;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.GridBagLayout;
import java.awt.Point;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ComponentEvent;
import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;
import java.awt.event.WindowEvent;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.beans.PropertyVetoException;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.swing.BorderFactory;
import javax.swing.DefaultDesktopManager;
import javax.swing.JDesktopPane;
import javax.swing.JFrame;
import javax.swing.JInternalFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.SwingConstants;
import javax.swing.SwingUtilities;
import javax.swing.Timer;
import javax.swing.WindowConstants;
import javax.swing.event.InternalFrameAdapter;
import javax.swing.event.InternalFrameEvent;
import javax.swing.event.InternalFrameListener;
import javax.swing.event.MenuEvent;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;
import org.openjump.core.model.TaskEvent;
import org.openjump.core.model.TaskListener;
import org.openjump.swing.factory.component.ComponentFactory;
import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.util.Assert;
import com.vividsolutions.jump.I18N;
import com.vividsolutions.jump.util.Blackboard;
import com.vividsolutions.jump.util.Block;
import com.vividsolutions.jump.util.CollectionUtil;
import com.vividsolutions.jump.util.StringUtil;
import com.vividsolutions.jump.workbench.JUMPWorkbench;
import com.vividsolutions.jump.workbench.WorkbenchContext;
import com.vividsolutions.jump.workbench.model.Category;
import com.vividsolutions.jump.workbench.model.CategoryEvent;
import com.vividsolutions.jump.workbench.model.FeatureEvent;
import com.vividsolutions.jump.workbench.model.Layer;
import com.vividsolutions.jump.workbench.model.LayerEvent;
import com.vividsolutions.jump.workbench.model.LayerEventType;
import com.vividsolutions.jump.workbench.model.LayerListener;
import com.vividsolutions.jump.workbench.model.LayerManager;
import com.vividsolutions.jump.workbench.model.LayerManagerProxy;
import com.vividsolutions.jump.workbench.model.Layerable;
import com.vividsolutions.jump.workbench.model.StandardCategoryNames;
import com.vividsolutions.jump.workbench.model.Task;
import com.vividsolutions.jump.workbench.model.UndoableEditReceiver;
import com.vividsolutions.jump.workbench.model.WMSLayer;
import com.vividsolutions.jump.workbench.plugin.AbstractPlugIn;
import com.vividsolutions.jump.workbench.plugin.EnableCheck;
import com.vividsolutions.jump.workbench.plugin.PlugIn;
import com.vividsolutions.jump.workbench.ui.plugin.FeatureInstaller;
import com.vividsolutions.jump.workbench.ui.plugin.PersistentBlackboardPlugIn;
import com.vividsolutions.jump.workbench.ui.renderer.style.ChoosableStyle;
import com.vividsolutions.jump.workbench.ui.task.TaskMonitorManager;
import javax.swing.JComponent;
import javax.swing.JSplitPane;
import javax.swing.JTextField;
/**
* This class is responsible for the main window of the JUMP application.
*/
public class WorkbenchFrame extends JFrame
implements LayerViewPanelContext, ViewportListener
{
BorderLayout borderLayout1 = new BorderLayout();
JLabel coordinateLabel = new JLabel();
JMenuBar menuBar = new JMenuBar();
JMenu fileMenu = (JMenu) FeatureInstaller.installMnemonic(new JMenu(
MenuNames.FILE), menuBar);
JMenuItem exitMenuItem = FeatureInstaller.installMnemonic(new JMenuItem(
I18N.get("ui.WorkbenchFrame.exit")), fileMenu);
JTextField messageTextField = new JTextField();
JPanel statusPanel = new JPanel();
JLabel timeLabel = new JLabel();
// the four SplitPanes for the statusbar
private JSplitPane statusPanelSplitPane1;
private JSplitPane statusPanelSplitPane2;
private JSplitPane statusPanelSplitPane3;
private JSplitPane statusPanelSplitPane4;
// <<TODO:FEATURE>> Before JUMP Workbench closes, prompt the user to save
// any
// unsaved layers [Jon Aquino]
WorkbenchToolBar toolBar;
JMenu windowMenu = (JMenu)FeatureInstaller.installMnemonic(new JMenu(
MenuNames.WINDOW), menuBar);
private DecimalFormat memoryFormat = new DecimalFormat("###,###");
private TitledPopupMenu categoryPopupMenu = new TitledPopupMenu() {
{
addPopupMenuListener(new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
LayerNamePanel panel = ((LayerNamePanelProxy)getActiveInternalFrame()).getLayerNamePanel();
setTitle((panel.selectedNodes(Category.class).size() != 1) ? ("("
+ panel.selectedNodes(Category.class).size() + " categories selected)")
: ((Category)panel.selectedNodes(Category.class).iterator().next()).getName());
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
}
};
private JDesktopPane desktopPane = new JDesktopPane() {
{
// Simple workaround for the following JUMP bug: if you maximize one
// JInternalFrame, then all
// JInternalFrames get maximized (including attribute windows,
// undesirably). The workaround is
// to use the DefaultDesktopManager instead of the one installed by the
// Windows L&F
// (the WindowsDesktopManager). (Uwe Dalluege noticed that the problem
// occurred with the
// Windows L&F but not the Metal L&F -- this observation led me to the
// solution).
// [Jon Aquino 2005-07-04]
setDesktopManager(new DefaultDesktopManager());
}
};
// <<TODO:REMOVE>> Actually we're not using the three optimization
// parameters
// below. Remove. [Jon Aquino]
private int envelopeRenderingThreshold = 500;
private HTMLFrame outputFrame = new HTMLFrame(this) {
public void setTitle(String title) {
// Don't allow the title of the output frame to be changed.
}
{
super.setTitle(I18N.get("ui.WorkbenchFrame.output"));
}
};
private TitledPopupMenu layerNamePopupMenu = new TitledPopupMenu() {
{
addPopupMenuListener(new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
LayerNamePanel panel = ((LayerNamePanelProxy)getActiveInternalFrame()).getLayerNamePanel();
setTitle((panel.selectedNodes(Layer.class).size() != 1) ? ("("
+ panel.selectedNodes(Layer.class).size() + " "
+ I18N.get("ui.WorkbenchFrame.layers-selected") + ")")
: ((Layerable)panel.selectedNodes(Layer.class).iterator().next()).getName());
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
}
};
private TitledPopupMenu wmsLayerNamePopupMenu = new TitledPopupMenu() {
{
addPopupMenuListener(new PopupMenuListener() {
public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
LayerNamePanel panel = ((LayerNamePanelProxy)getActiveInternalFrame()).getLayerNamePanel();
setTitle((panel.selectedNodes(WMSLayer.class).size() != 1) ? ("("
+ panel.selectedNodes(WMSLayer.class).size() + " "
+ I18N.get("ui.WorkbenchFrame.wms-layers-selected") + ")")
: ((Layerable)panel.selectedNodes(WMSLayer.class).iterator().next()).getName());
}
public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
}
public void popupMenuCanceled(PopupMenuEvent e) {
}
});
}
};
private LayerNamePanelListener layerNamePanelListener = new LayerNamePanelListener() {
public void layerSelectionChanged() {
toolBar.updateEnabledState();
}
};
// Here is a small patch to JUMP to avoid creating a StringBuffer every
// coordinate change (which could be many thoustands). Replace the innter
// class in WorkbenchFrame.java with the following. I am assuming only one
// thread can call the listener at a time. If that is untrue please
// synchronize
// cursorPositionChanged().
//
// Sheldon Young 2004-01-30
private LayerViewPanelListener layerViewPanelListener = new LayerViewPanelListener() {
// Avoid creating an expensive StringBuffer when the cursor position
// changes.
private StringBuffer positionStatusBuf = new StringBuffer("(");
public void cursorPositionChanged(String x, String y) {
positionStatusBuf.setLength(1);
positionStatusBuf.append(x).append(", ").append(y).append(")");
coordinateLabel.setText(positionStatusBuf.toString());
}
public void selectionChanged() {
toolBar.updateEnabledState();
}
public void fenceChanged() {
toolBar.updateEnabledState();
}
public void painted(Graphics graphics) {
}
};
// <<TODO:NAMING>> This name is not clear [Jon Aquino]
private int maximumFeatureExtentForEnvelopeRenderingInPixels = 10;
// <<TODO:NAMING>> This name is not clear [Jon Aquino]
private int minimumFeatureExtentForAnyRenderingInPixels = 2;
private StringBuffer log = new StringBuffer();
private int taskSequence = 1;
private WorkbenchContext workbenchContext;
private JLabel memoryLabel = new JLabel();
private String lastStatusMessage = "";
private Set choosableStyleClasses = new HashSet();
private JLabel wmsLabel = new JLabel();
private ArrayList easyKeyListeners = new ArrayList();
private ArrayList<TaskListener> taskListeners = new ArrayList<TaskListener>();
private Map nodeClassToLayerNamePopupMenuMap = CollectionUtil.createMap(new Object[] {
Layer.class, layerNamePopupMenu, WMSLayer.class, wmsLayerNamePopupMenu,
Category.class, categoryPopupMenu
});
private int positionIndex = -1;
private int primaryInfoFrameIndex = -1;
private int addedMenuItems = -1;
private ComponentFactory<TaskFrame> taskFrameFactory;
public WorkbenchFrame(String title, final WorkbenchContext workbenchContext) throws Exception {
setTitle(title);
new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent e) {
memoryLabel.setText(getMBCommittedMemory() + " MB "
+ I18N.get("ui.WorkbenchFrame.committed-memory"));
//memoryLabel.setToolTipText(LayerManager.layerManagerCount() + " "
// + I18N.get("ui.WorkbenchFrame.layer-manager")
// + StringUtil.s(LayerManager.layerManagerCount()));
}
}).start();
this.workbenchContext = workbenchContext;
// set icon for the app frame
JUMPWorkbench.setIcon(this);
//this.icon = new ImageIcon();
//this.icon.setImage(JUMPWorkbench.getIcon());
toolBar = new WorkbenchToolBar(workbenchContext);
toolBar.setTaskMonitorManager(new TaskMonitorManager());
try {
jbInit();
configureStatusLabel(messageTextField, 300);
configureStatusLabel(coordinateLabel, 150);
configureStatusLabel(timeLabel, 200);
configureStatusLabel(wmsLabel, 100);
} catch (Exception e) {
e.printStackTrace();
}
new RecursiveKeyListener(this) {
public void keyTyped(KeyEvent e) {
for (Iterator i = easyKeyListeners.iterator(); i.hasNext();) {
KeyListener l = (KeyListener)i.next();
l.keyTyped(e);
}
}
public void keyPressed(KeyEvent e) {
for (Iterator i = new ArrayList(easyKeyListeners).iterator(); i.hasNext();) {
KeyListener l = (KeyListener)i.next();
l.keyPressed(e);
}
}
public void keyReleased(KeyEvent e) {
for (Iterator i = new ArrayList(easyKeyListeners).iterator(); i.hasNext();) {
KeyListener l = (KeyListener)i.next();
l.keyReleased(e);
}
}
};
installKeyboardShortcutListener();
}
/**
* Unlike #add(KeyListener), listeners registered using this method are
* notified when KeyEvents occur on this frame's child components. Note: Bug:
* KeyListeners registered using this method may receive events multiple
* times.
*
* @see #addKeyboardShortcut
*/
public void addEasyKeyListener(KeyListener l) {
easyKeyListeners.add(l);
}
public void removeEasyKeyListener(KeyListener l) {
easyKeyListeners.remove(l);
}
public String getMBCommittedMemory() {
long totalMemory = Runtime.getRuntime().totalMemory();
long freeMemory = Runtime.getRuntime().freeMemory();
long usedMemory = totalMemory - freeMemory;
double usedMemoryInMB = usedMemory / (1024 * 1024d);
String memoryStr = memoryFormat.format(usedMemoryInMB);
return memoryStr;
}
/**
* @param newEnvelopeRenderingThreshold the number of on-screen features above
* which envelope rendering should occur
*/
public void setEnvelopeRenderingThreshold(int newEnvelopeRenderingThreshold) {
envelopeRenderingThreshold = newEnvelopeRenderingThreshold;
}
public void setMaximumFeatureExtentForEnvelopeRenderingInPixels(
int newMaximumFeatureExtentForEnvelopeRenderingInPixels) {
maximumFeatureExtentForEnvelopeRenderingInPixels = newMaximumFeatureExtentForEnvelopeRenderingInPixels;
}
public void log(String message) {
log.append(new Date() + " " + message
+ System.getProperty("line.separator"));
}
public String getLog() {
return log.toString();
}
public void setMinimumFeatureExtentForAnyRenderingInPixels(
int newMinimumFeatureExtentForAnyRenderingInPixels) {
minimumFeatureExtentForAnyRenderingInPixels = newMinimumFeatureExtentForAnyRenderingInPixels;
}
public void displayLastStatusMessage() {
setStatusMessage(lastStatusMessage);
}
public void setStatusMessage(String message) {
lastStatusMessage = message;
setStatusBarText(message);
setStatusBarTextHighlighted(false, null);
}
private void setStatusBarText(String message) {
// <<TODO:IMPROVE>> Treat null messages like "" [Jon Aquino]
messageTextField.setText(message.equals("") ? " " : message);
// Make message at least a space so that status bar won't collapse [Jon
// Aquino]
}
/**
* To highlight a message, call #warnUser.
*/
private void setStatusBarTextHighlighted(boolean highlighted, Color color) {
// Use #coordinateLabel rather than (unattached) dummy label because
// dummy label's background does not change when L&F changes. [Jon
// Aquino]
messageTextField.setForeground(highlighted ? Color.black
: coordinateLabel.getForeground());
messageTextField.setBackground(highlighted ? color
: coordinateLabel.getBackground());
}
public void setTimeMessage(String message) {
// <<TODO:IMPROVE>> Treat null messages like "" [Jon Aquino]
timeLabel.setText(message.equals("") ? " " : message);
timeLabel.setToolTipText(message);
// Make message at least a space so that status bar won't collapse [Jon
// Aquino]
}
public JInternalFrame getActiveInternalFrame() {
return desktopPane.getSelectedFrame();
}
public JInternalFrame[] getInternalFrames() {
return desktopPane.getAllFrames();
}
public TitledPopupMenu getCategoryPopupMenu() {
return categoryPopupMenu;
}
public WorkbenchContext getContext() {
return workbenchContext;
}
public JDesktopPane getDesktopPane() {
return desktopPane;
}
public int getEnvelopeRenderingThreshold() {
return envelopeRenderingThreshold;
}
public TitledPopupMenu getLayerNamePopupMenu() {
return layerNamePopupMenu;
}
public TitledPopupMenu getWMSLayerNamePopupMenu() {
return wmsLayerNamePopupMenu;
}
public LayerViewPanelListener getLayerViewPanelListener() {
return layerViewPanelListener;
}
public Map getNodeClassToPopupMenuMap() {
return nodeClassToLayerNamePopupMenuMap;
}
public LayerNamePanelListener getLayerNamePanelListener() {
return layerNamePanelListener;
}
public int getMaximumFeatureExtentForEnvelopeRenderingInPixels() {
return maximumFeatureExtentForEnvelopeRenderingInPixels;
}
public int getMinimumFeatureExtentForAnyRenderingInPixels() {
return minimumFeatureExtentForAnyRenderingInPixels;
}
public HTMLFrame getOutputFrame() {
return outputFrame;
}
public WorkbenchToolBar getToolBar() {
return toolBar;
}
public void activateFrame(JInternalFrame frame) {
try {
if (frame.isIcon()) {
frame.setIcon(false);
}
frame.moveToFront();
frame.requestFocus();
frame.setSelected(true);
if (!(frame instanceof TaskFrame)) {
frame.setMaximum(false);
}
} catch (PropertyVetoException e) {
warnUser(StringUtil.stackTrace(e));
}
}
/**
* If internalFrame is a LayerManagerProxy, the close behaviour will be
* altered so that the user is prompted if it is the last window on the
* LayerManager.
*/
public void addInternalFrame(final JInternalFrame internalFrame) {
addInternalFrame(internalFrame, false, true);
}
public void addInternalFrame(final JInternalFrame internalFrame,
boolean alwaysOnTop, boolean autoUpdateToolBar) {
if (internalFrame instanceof LayerManagerProxy) {
setClosingBehaviour((LayerManagerProxy)internalFrame);
installTitleBarModifiedIndicator((LayerManagerProxy)internalFrame);
}
// <<TODO:IMPROVE>> Listen for when the frame closes, and when it does,
// activate the topmost frame. Because Swing does not seem to do this
// automatically. [Jon Aquino]
JUMPWorkbench.setIcon( internalFrame );
// Call JInternalFrame#setVisible before JDesktopPane#add; otherwise,
// the
// TreeLayerNamePanel starts too narrow (100 pixels or so) for some
// reason.
// <<TODO>>Investigate. [Jon Aquino]
internalFrame.setVisible(true);
desktopPane.add(internalFrame, alwaysOnTop ? JLayeredPane.PALETTE_LAYER
: JLayeredPane.DEFAULT_LAYER);
if (autoUpdateToolBar) {
internalFrame.addInternalFrameListener(new InternalFrameListener() {
public void internalFrameActivated(InternalFrameEvent e) {
toolBar.updateEnabledState();
// Associate current cursortool with the new frame [Jon
// Aquino]
toolBar.reClickSelectedCursorToolButton();
}
public void internalFrameClosed(InternalFrameEvent e) {
toolBar.updateEnabledState();
}
public void internalFrameClosing(InternalFrameEvent e) {
toolBar.updateEnabledState();
}
public void internalFrameDeactivated(InternalFrameEvent e) {
toolBar.updateEnabledState();
}
public void internalFrameDeiconified(InternalFrameEvent e) {
toolBar.updateEnabledState();
}
public void internalFrameIconified(InternalFrameEvent e) {
toolBar.updateEnabledState();
}
public void internalFrameOpened(InternalFrameEvent e) {
toolBar.updateEnabledState();
}
});
// Call #activateFrame *after* adding the listener. [Jon Aquino]
activateFrame(internalFrame);
position(internalFrame);
}
}
private void installTitleBarModifiedIndicator(
final LayerManagerProxy internalFrame) {
final JInternalFrame i = (JInternalFrame)internalFrame;
new Block() {
// Putting updatingTitle in a Block is better than making it an
// instance variable, because this way there is one updatingTitle
// for each
// internal frame, rather than one for all internal frames. [Jon
// Aquino]
private boolean updatingTitle = false;
private void updateTitle() {
if (updatingTitle) {
return;
}
updatingTitle = true;
try {
String newTitle = i.getTitle();
if (newTitle.charAt(0) == '*') {
newTitle = newTitle.substring(1);
}
if (!internalFrame.getLayerManager()
.getLayersWithModifiedFeatureCollections()
.isEmpty()) {
newTitle = '*' + newTitle;
}
i.setTitle(newTitle);
} finally {
updatingTitle = false;
}
}
public Object yield() {
internalFrame.getLayerManager().addLayerListener(new LayerListener() {
public void layerChanged(LayerEvent e) {
if ((e.getType() == LayerEventType.METADATA_CHANGED)
|| (e.getType() == LayerEventType.REMOVED)) {
updateTitle();
}
}
public void categoryChanged(CategoryEvent e) {
}
public void featuresChanged(FeatureEvent e) {
}
});
i.addPropertyChangeListener(JInternalFrame.TITLE_PROPERTY,
new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent e) {
updateTitle();
}
});
return null;
}
}.yield();
}
private void setClosingBehaviour(final LayerManagerProxy proxy) {
final JInternalFrame internalFrame = (JInternalFrame)proxy;
internalFrame.setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE);
internalFrame.addInternalFrameListener(new InternalFrameAdapter() {
public void internalFrameClosing(InternalFrameEvent e) {
internalFrameCloseHandler.close(internalFrame);
}
});
}
private Collection getInternalFramesAssociatedWith(LayerManager layerManager) {
ArrayList internalFramesAssociatedWithLayerManager = new ArrayList();
JInternalFrame[] internalFrames = getInternalFrames();
for (int i = 0; i < internalFrames.length; i++) {
if (internalFrames[i] instanceof LayerManagerProxy
&& (((LayerManagerProxy)internalFrames[i]).getLayerManager() == layerManager)) {
internalFramesAssociatedWithLayerManager.add(internalFrames[i]);
}
}
return internalFramesAssociatedWithLayerManager;
}
// added by [mmichaud 2007-06-03]
// Return TaskFrame s using the same layerManager
private Collection getTaskFramesAssociatedWith(LayerManager layerManager) {
ArrayList taskFramesAssociatedWithLayerManager = new ArrayList();
JInternalFrame[] internalFrames = getInternalFrames();
for (int i = 0; i < internalFrames.length; i++) {
if (internalFrames[i] instanceof TaskFrame
&& (((TaskFrame)internalFrames[i]).getLayerManager() == layerManager)) {
taskFramesAssociatedWithLayerManager.add(internalFrames[i]);
}
}
return taskFramesAssociatedWithLayerManager;
}
// added by [mmichaud 2007-06-03]
// Return every InternalFrame associated with taskFrame (taskFrame is
// excluded)
private Collection getInternalFramesAssociatedWith(TaskFrame taskFrame) {
ArrayList internalFramesAssociatedWithTaskFrame = new ArrayList();
JInternalFrame[] internalFrames = getInternalFrames();
for (int i = 0; i < internalFrames.length; i++) {
if (internalFrames[i] instanceof TaskFrameProxy
&& (((TaskFrameProxy)internalFrames[i]).getTaskFrame() == taskFrame)
&& internalFrames[i] != taskFrame) {
internalFramesAssociatedWithTaskFrame.add(internalFrames[i]);
}
}
return internalFramesAssociatedWithTaskFrame;
}
public TaskFrame addTaskFrame() {
TaskFrame f = addTaskFrame(createTask());
return f;
}
public Task createTask() {
Task task = new Task();
// LayerManager shouldn't automatically add categories in its
// constructor.
// Sometimes we want to create a LayerManager with no categories
// (e.g. in OpenProjectPlugIn). [Jon Aquino]
task.getLayerManager().addCategory(StandardCategoryNames.WORKING);
task.getLayerManager().addCategory(StandardCategoryNames.SYSTEM);
task.setName(I18N.get("ui.WorkbenchFrame.task") + " " + taskSequence++);
return task;
}
public TaskFrame addTaskFrame(Task task) {
TaskFrame taskFrame;
if (taskFrameFactory != null) {
taskFrame = taskFrameFactory.createComponent();
taskFrame.setTask(task);
} else {
taskFrame = new TaskFrame(task, workbenchContext);
}
return addTaskFrame(taskFrame);
}
public TaskFrame addTaskFrame(TaskFrame taskFrame) {
taskFrame.getTask().getLayerManager().addLayerListener(new LayerListener() {
public void featuresChanged(FeatureEvent e) {
}
public void categoryChanged(CategoryEvent e) {
toolBar.updateEnabledState();
}
public void layerChanged(LayerEvent layerEvent) {
toolBar.updateEnabledState();
}
});
addInternalFrame(taskFrame);
taskFrame.getLayerViewPanel()
.getLayerManager()
.getUndoableEditReceiver()
.add(new UndoableEditReceiver.Listener() {
public void undoHistoryChanged() {
toolBar.updateEnabledState();
}
public void undoHistoryTruncated() {
toolBar.updateEnabledState();
log(I18N.get("ui.WorkbenchFrame.undo-history-was-truncated"));
}
});
// fire TaskListener's
Object[] listeners = getTaskListeners().toArray();
for (int i = 0; i < listeners.length; i++) {
TaskListener l = (TaskListener) listeners[i];
l.taskAdded(new TaskEvent(this, taskFrame.getTask()));
}
return taskFrame;
}
public void flash(final HTMLFrame frame) {
final Color originalColor = frame.getBackgroundColor();
new Timer(100, new ActionListener() {
private int tickCount = 0;
public void actionPerformed(ActionEvent e) {
try {
tickCount++;
frame.setBackgroundColor(((tickCount % 2) == 0) ? originalColor
: Color.yellow);
if (tickCount == 2) {
Timer timer = (Timer)e.getSource();
timer.stop();
}
} catch (Throwable t) {
handleThrowable(t);
}
}
}).start();
}
private void flashStatusMessage(final String message, final Color color) {
new Timer(100, new ActionListener() {
private int tickCount = 0;
public void actionPerformed(ActionEvent e) {
tickCount++;
// This message is important, so overwrite whatever is on the
// status bar. [Jon Aquino]
setStatusBarText(message);
setStatusBarTextHighlighted((tickCount % 2) == 0, color);
if (tickCount == 4) {
Timer timer = (Timer)e.getSource();
timer.stop();
}
}
}).start();
}
/**
* Can be called regardless of whether the current thread is the AWT event
* dispatch thread.
*
* @param t Description of the Parameter
*/
public void handleThrowable(final Throwable t) {
log(StringUtil.stackTrace(t));
Component parent = this;
Window[] ownedWindows = getOwnedWindows();
for (int i = 0; i < ownedWindows.length; i++) {
if (ownedWindows[i] instanceof Dialog && ownedWindows[i].isVisible()
&& ((Dialog)ownedWindows[i]).isModal()) {
parent = ownedWindows[i];
break;
}
}
handleThrowable(t, parent);
}
public static void handleThrowable(final Throwable t, final Component parent) {
t.printStackTrace(System.err);
SwingUtilities.invokeLater(new Runnable() {
public void run() {
ErrorDialog.show(parent, StringUtil.toFriendlyName(t.getClass()
.getName()), toMessage(t), StringUtil.stackTrace(t));
}
});
}
private ArrayList lastFiveThrowableDates = new ArrayList() {
public boolean add(Object o) {
if (size() == 5) {
remove(0);
}
return super.add(o);
}
};
public static String toMessage(Throwable t) {
String message;
if (t.getLocalizedMessage() == null) {
message = I18N.get("ui.WorkbenchFrame.no-description-was-provided");
} else if (t.getLocalizedMessage().toLowerCase().indexOf(
I18N.get("ui.WorkbenchFrame.side-location-conflict")) > -1) {
message = t.getLocalizedMessage() + " -- "
+ I18N.get("ui.WorkbenchFrame.check-for-invalid-geometries");
} else {
message = t.getLocalizedMessage();
}
return message + " (" + StringUtil.toFriendlyName(t.getClass().getName())
+ ")";
}
public boolean hasInternalFrame(JInternalFrame internalFrame) {
JInternalFrame[] frames = desktopPane.getAllFrames();
for (int i = 0; i < frames.length; i++) {
if (frames[i] == internalFrame) {
return true;
}
}
return false;
}
public void removeInternalFrame(JInternalFrame internalFrame) {
// Looks like #closeFrame is the proper way to remove an internal
// frame.
// It will activate the next frame. [Jon Aquino]
desktopPane.getDesktopManager().closeFrame(internalFrame);
}
public void warnUser(String warning) {
log(I18N.get("ui.WorkbenchFrame.warning") + ": " + warning);
flashStatusMessage(warning, Color.yellow);
}
public void zoomChanged(Envelope modelEnvelope) {
toolBar.updateEnabledState();
}
void exitMenuItem_actionPerformed(ActionEvent e) {
closeApplication();
}
void this_componentShown(ComponentEvent e) {
try {
// If the first internal frame is not a TaskWindow (as may be the
// case in
// custom workbenches), #updateEnabledState() will ensure that the
// cursor-tool buttons are disabled. [Jon Aquino]
toolBar.updateEnabledState();
} catch (Throwable t) {
handleThrowable(t);
}
}
void this_windowClosing(WindowEvent e) {
closeApplication();
}
void windowMenu_menuSelected(MenuEvent e) {
// If this is the first call get the number of added menu items.
// After this point no new menus can be added
if (addedMenuItems == -1) {
addedMenuItems = windowMenu.getItemCount();
}
while (windowMenu.getItemCount() > addedMenuItems) {
windowMenu.remove(windowMenu.getItemCount() - 1);
}
final JInternalFrame[] frames = desktopPane.getAllFrames();
for (int i = 0; i < frames.length; i++) {
JMenuItem menuItem = new JMenuItem();
// Increase truncation threshold from 20 to 40, for eziLink [Jon
// Aquino]
menuItem.setText(GUIUtil.truncateString(frames[i].getTitle(), 40));
associate(menuItem, frames[i]);
windowMenu.add(menuItem);
}
if (windowMenu.getItemCount() == addedMenuItems) {
// For ezLink [Jon Aquino]
windowMenu.add(new JMenuItem("("
+ I18N.get("ui.WorkbenchFrame.no-windows") + ")"));
}
}
private void associate(JMenuItem menuItem, final JInternalFrame frame) {
menuItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
try {
activateFrame(frame);
} catch (Throwable t) {
handleThrowable(t);
}
}
});
}
private void closeApplication() {
applicationExitHandler.exitApplication(this);
}
private Collection getLayersWithModifiedFeatureCollections() {
ArrayList layersWithModifiedFeatureCollections = new ArrayList();
for (Iterator i = getLayerManagers().iterator(); i.hasNext();) {
LayerManager layerManager = (LayerManager)i.next();
layersWithModifiedFeatureCollections.addAll(layerManager.getLayersWithModifiedFeatureCollections());
}
return layersWithModifiedFeatureCollections;
}
private Collection getGeneratedLayers() {
ArrayList list = new ArrayList();
for (Iterator i = getLayerManagers().iterator(); i.hasNext();) {
LayerManager layerManager = (LayerManager)i.next();
list.addAll(layerManager.getLayersWithNullDataSource());
}
return list;
}
private Collection getLayerManagers() {
// Multiple windows may point to the same LayerManager, so use
// a Set. [Jon Aquino]
HashSet layerManagers = new HashSet();
JInternalFrame[] internalFrames = getInternalFrames();
for (int i = 0; i < internalFrames.length; i++) {
if (internalFrames[i] instanceof LayerManagerProxy) {
layerManagers.add(((LayerManagerProxy)internalFrames[i]).getLayerManager());
}
}
return layerManagers;
}
private void configureStatusLabel(JComponent component, int width) {
component.setMinimumSize(new Dimension(width, (int)component.getMinimumSize()
.getHeight()));
component.setMaximumSize(new Dimension(width, (int)component.getMaximumSize()
.getHeight()));
component.setPreferredSize(new Dimension(width, (int)component.getPreferredSize()
.getHeight()));
}
private void jbInit() throws Exception {
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
// TODO: insert icon necessary?
//JUMPWorkbench.setIcon( this );
this.addComponentListener(new java.awt.event.ComponentAdapter() {
public void componentShown(ComponentEvent e) {
this_componentShown(e);
}
});
this.getContentPane().setLayout(borderLayout1);
this.addWindowListener(new java.awt.event.WindowAdapter() {
public void windowClosing(WindowEvent e) {
this_windowClosing(e);
}
});
this.setJMenuBar(menuBar);
// This size is chosen so that when the user hits the Info tool, the
// window
// fits between the lower edge of the TaskFrame and the lower edge of
// the
// WorkbenchFrame. See the call to #setSize in InfoFrame. [Jon Aquino]
setSize(900, 665);
// OUTLINE_DRAG_MODE is excruciatingly slow in JDK 1.4.1, so don't use
// it.
// (although it's supposed to be fixed in 1.4.2, which has not yet been
// released). (see Sun Java Bug ID 4665237). [Jon Aquino]
// desktopPane.setDragMode(JDesktopPane.OUTLINE_DRAG_MODE);
messageTextField.setOpaque(true);
messageTextField.setEditable(false);
messageTextField.setToolTipText(I18N.get("ui.WorkbenchFrame.copy-to-clipboard"));
messageTextField.setFont(coordinateLabel.getFont());
memoryLabel.setText("jLabel1");
wmsLabel.setHorizontalAlignment(SwingConstants.LEFT);
wmsLabel.setText(" ");
this.getContentPane().add(statusPanel, BorderLayout.SOUTH);
exitMenuItem.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
exitMenuItem_actionPerformed(e);
}
});
windowMenu.addMenuListener(new javax.swing.event.MenuListener() {
public void menuCanceled(MenuEvent e) {
}
public void menuDeselected(MenuEvent e) {
}
public void menuSelected(MenuEvent e) {
windowMenu_menuSelected(e);
}
});
coordinateLabel.setBorder(BorderFactory.createLoweredBevelBorder());
wmsLabel.setBorder(BorderFactory.createLoweredBevelBorder());
coordinateLabel.setText(" ");
//messageTextField.setBorder(BorderFactory.createLoweredBevelBorder());
messageTextField.setText(" ");
timeLabel.setBorder(BorderFactory.createLoweredBevelBorder());
timeLabel.setText(" ");
memoryLabel.setBorder(BorderFactory.createLoweredBevelBorder());
memoryLabel.setText(" ");
menuBar.add(fileMenu);
menuBar.add(windowMenu);
getContentPane().add(toolBar, BorderLayout.NORTH);
getContentPane().add(desktopPane, BorderLayout.CENTER);
fileMenu.addSeparator();
fileMenu.add(exitMenuItem);
// [Matthias Scholz 11. Dec 2010] new resizable stausbar
statusPanel.setLayout(new BorderLayout());
int dividerSize = 4;
statusPanelSplitPane4 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, wmsLabel, coordinateLabel);
statusPanelSplitPane4.setDividerSize(dividerSize);
statusPanelSplitPane3 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, memoryLabel, statusPanelSplitPane4);
statusPanelSplitPane3.setDividerSize(dividerSize);
statusPanelSplitPane2 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, timeLabel, statusPanelSplitPane3);
statusPanelSplitPane2.setDividerSize(dividerSize);
statusPanelSplitPane1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT, true, messageTextField, statusPanelSplitPane2);
statusPanelSplitPane1.setDividerSize(dividerSize);
// Workaround for java bug 4131528
statusPanelSplitPane1.setBorder(null);
statusPanelSplitPane2.setBorder(null);
statusPanelSplitPane3.setBorder(null);
statusPanelSplitPane4.setBorder(null);
statusPanel.add(statusPanelSplitPane1, BorderLayout.CENTER);
}
private void position(JInternalFrame internalFrame) {
final int STEP = 5;
GUIUtil.Location location = null;
if (internalFrame instanceof PrimaryInfoFrame) {
primaryInfoFrameIndex++;
int offset = (primaryInfoFrameIndex % 3) * STEP;
location = new GUIUtil.Location(offset, true, offset, true);
} else {
positionIndex++;
int offset = (positionIndex % 5) * STEP;
location = new GUIUtil.Location(offset, false, offset, false);
}
GUIUtil.setLocation(internalFrame, location, desktopPane);
}
/**
* Fundamental Style classes (like BasicStyle, VertexStyle, and LabelStyle)
* cannot be removed, and are thus excluded from the choosable Style classes.
*/
public Set getChoosableStyleClasses() {
return Collections.unmodifiableSet(choosableStyleClasses);
}
public void addChoosableStyleClass(Class choosableStyleClass) {
Assert.isTrue(ChoosableStyle.class.isAssignableFrom(choosableStyleClass));
choosableStyleClasses.add(choosableStyleClass);
}
private HashMap keyCodeAndModifiersToPlugInAndEnableCheckMap = new HashMap();
/**
* Adds a keyboard shortcut for a plugin. logs plugin exceptions. note -
* attaching to keyCode 'a', modifiers =1 will detect shift-A events. It will
* *not* detect caps-lock-'a'. This is due to inconsistencies in
* java.awt.event.KeyEvent. In the unlikely event you actually do want to also
* also attach to caps-lock-'a', then make two shortcuts - one to keyCode 'a'
* and modifiers =1 (shift-A) and one to keyCode 'A' and modifiers=0
* (caps-lock A). For more details, see the java.awt.event.KeyEvent class - it
* has a full explaination.
*
* @param keyCode What key to attach to (See java.awt.event.KeyEvent)
* @param modifiers 0= none, 1=shift, 2= cntrl, 8=alt, 3=shift+cntrl, etc...
* See the modifier mask constants in the Event class
* @param plugIn What plugin to execute
* @param enableCheck Is the key enabled at the moment?
*/
public void addKeyboardShortcut(final int keyCode, final int modifiers,
final PlugIn plugIn, final EnableCheck enableCheck) {
// Overwrite existing shortcut [Jon Aquino]
keyCodeAndModifiersToPlugInAndEnableCheckMap.put(keyCode + ":" + modifiers,
new Object[] {
plugIn, enableCheck
});
}
private void installKeyboardShortcutListener() {
addEasyKeyListener(new KeyListener() {
public void keyTyped(KeyEvent e) {
}
public void keyReleased(KeyEvent e) {
}
public void keyPressed(KeyEvent e) {
Object[] plugInAndEnableCheck = (Object[])keyCodeAndModifiersToPlugInAndEnableCheckMap.get(e.getKeyCode()
+ ":" + e.getModifiers());
if (plugInAndEnableCheck == null) {
return;
}
PlugIn plugIn = (PlugIn)plugInAndEnableCheck[0];
EnableCheck enableCheck = (EnableCheck)plugInAndEnableCheck[1];
if (enableCheck != null && enableCheck.check(null) != null) {
return;
}
// #toActionListener handles checking if the plugIn is a
// ThreadedPlugIn,
// and making calls to UndoableEditReceiver if necessary. [Jon
// Aquino 10/15/2003]
AbstractPlugIn.toActionListener(plugIn, workbenchContext,
new TaskMonitorManager()).actionPerformed(null);
}
});
}
// ==========================================================================
// Applications (such as EziLink) want to override the default JUMP
// frame closing behaviour and application exit behaviour with their own
// behaviours.
//
InternalFrameCloseHandler internalFrameCloseHandler = new DefaultInternalFrameCloser();
ApplicationExitHandler applicationExitHandler = new DefaultApplicationExitHandler();
public InternalFrameCloseHandler getInternalFrameCloseHandler() {
return internalFrameCloseHandler;
}
public void setInternalFrameCloseHandler(InternalFrameCloseHandler value) {
internalFrameCloseHandler = value;
}
public ApplicationExitHandler getApplicationExitHandler() {
return applicationExitHandler;
}
public void setApplicationExitHandler(ApplicationExitHandler value) {
applicationExitHandler = value;
}
private class DefaultInternalFrameCloser implements InternalFrameCloseHandler {
public void close(JInternalFrame internalFrame) {
if (internalFrame instanceof TaskFrame) {
closeTaskFrame((TaskFrame)internalFrame);
} else {
GUIUtil.dispose(internalFrame, desktopPane);
}
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.runFinalization();
System.gc();
}
});
}
}
private class DefaultApplicationExitHandler implements ApplicationExitHandler {
public void exitApplication(JFrame mainFrame) {
if (confirmClose(I18N.get("ui.WorkbenchFrame.exit-jump"),
getLayersWithModifiedFeatureCollections(),
getGeneratedLayers())) {
// PersistentBlackboardPlugIn listens for when the workbench is
// hidden [Jon Aquino]
saveWindowState();
setVisible(false);
// Invoke System#exit after all pending GUI events have been
// fired
// (e.g. the hiding of this WorkbenchFrame) [Jon Aquino]
SwingUtilities.invokeLater(new Runnable() {
public void run() {
System.exit(0);
}
});
}
}
}
// Method completed by [mmichaud 2007-06-03] to close properly
// internal frames depending on a TaskFrame.
// Maybe this method should take place in TaskFrame instead...
private void closeTaskFrame(TaskFrame taskFrame) {
LayerManager layerManager = taskFrame.getLayerManager();
Collection associatedFrames = getInternalFramesAssociatedWith(taskFrame);
boolean lastTaskFrame = getTaskFramesAssociatedWith(layerManager).size() == 1;
if (lastTaskFrame) {
Collection modifiedItems = layerManager.getLayersWithModifiedFeatureCollections();
Collection generatedItems = layerManager.getLayersWithNullDataSource();
if (confirmClose(I18N.get("ui.WorkbenchFrame.close-task"), modifiedItems, generatedItems)) {
// There are other internal frames associated with this task
if (associatedFrames.size() != 0) {
// Confirm you want to close them first
if (confirmClose(
StringUtil.split(
I18N.get("ui.WorkbenchFrame.other-internal-frames-depend-on-this-task-frame")
+ " "
+ I18N.get("ui.WorkbenchFrame.do-you-want-to-close-them-also"),
60), I18N.get("ui.WorkbenchFrame.close-all"))) {
for (java.util.Iterator it = associatedFrames.iterator(); it.hasNext();) {
GUIUtil.dispose((JInternalFrame)it.next(), desktopPane);
}
} else
return; // finally, I don't want to close
}
layerManager.dispose();
taskFrame.getLayerViewPanel().dispose();
taskFrame.getLayerNamePanel().dispose();
GUIUtil.dispose(taskFrame, desktopPane);
} else
return; // finally, I don't want to close
} else {
// There are other internal frames associated with this task
if (associatedFrames.size() != 0) {
// Confirm you want to close them first
if (confirmClose(
StringUtil.split(
I18N.get("ui.WorkbenchFrame.other-internal-frames-depend-on-this-task-frame")
+ " "
+ I18N.get("ui.WorkbenchFrame.do-you-want-to-close-them-also"),
60), I18N.get("ui.WorkbenchFrame.close-all"))) {
for (java.util.Iterator it = associatedFrames.iterator(); it.hasNext();) {
GUIUtil.dispose((JInternalFrame)it.next(), desktopPane);
}
} else
return; // finally, I don't want to close
}
taskFrame.getLayerViewPanel().dispose();
taskFrame.getLayerNamePanel().dispose();
GUIUtil.dispose(taskFrame, desktopPane);
}
}
private boolean confirmClose(String action, Collection modifiedLayers, Collection generatedLayers) {
if (modifiedLayers.isEmpty()) {
if(generatedLayers.isEmpty()){
return true;
}
JOptionPane pane = new JOptionPane(I18N.getMessage("ui.WorkbenchFrame.do-you-really-want-to-close-openjump-generated-layers-not-saved", new Object[]{Integer.valueOf(generatedLayers.size())}),
JOptionPane.QUESTION_MESSAGE);
pane.setOptions(new String[] {
action, I18N.get("ui.WorkbenchFrame.cancel")
});
pane.createDialog(this, "JUMP").setVisible(true);
return pane.getValue().equals(action);
}
JOptionPane pane = new JOptionPane(
StringUtil.split(
modifiedLayers.size()
+ " "
+ I18N.get("ui.WorkbenchFrame.dataset")
+ StringUtil.s(modifiedLayers.size())
+ " "
+ ((modifiedLayers.size() > 1) ? I18N.get("ui.WorkbenchFrame.have-been-modified")
: I18N.get("ui.WorkbenchFrame.has-been-modified"))
+ " ("
+ ((modifiedLayers.size() > 3) ? "e.g. " : "")
+ StringUtil.toCommaDelimitedString(new ArrayList(modifiedLayers).subList(
0, Math.min(3, modifiedLayers.size()))) + "). "
+ I18N.get("ui.WorkbenchFrame.continue") + "?", 80),
JOptionPane.WARNING_MESSAGE);
pane.setOptions(new String[] {
action, I18N.get("ui.WorkbenchFrame.cancel")
});
pane.createDialog(this, "JUMP").setVisible(true);
return pane.getValue().equals(action);
}
private boolean confirmClose(String question, String action) {
javax.swing.JOptionPane pane = new javax.swing.JOptionPane(question,
javax.swing.JOptionPane.WARNING_MESSAGE);
pane.setOptions(new String[] {
action, com.vividsolutions.jump.I18N.get("ui.WorkbenchFrame.cancel")
});
pane.createDialog(this, "JUMP").setVisible(true);
return pane.getValue().equals(action);
}
/**
* @param taskFrameFactory the taskFrameFactory to set
*/
public void setTaskFrameFactory(ComponentFactory<TaskFrame> taskFrameFactory) {
this.taskFrameFactory = taskFrameFactory;
}
public final static String MAXIMIZED_KEY = WorkbenchFrame.class.getName()+" - MAXIMIZED_KEY";
public final static String HORIZONTAL_KEY = WorkbenchFrame.class.getName()+" - HORIZONTAL_KEY";
public final static String VERTICAL_KEY = WorkbenchFrame.class.getName()+" - VERTICAL_KEY";
public final static String WIDTH_KEY = WorkbenchFrame.class.getName()+" - WIDTH_KEY";
public final static String HEIGHT_KEY = WorkbenchFrame.class.getName()+" - HEIGHT_KEY";
public final static String STATUSPANEL_DIVIDER_LOCATION_1 = WorkbenchFrame.class.getName() + " - STATUSPANEL_DIVIDER_LOCATION_1";
public final static String STATUSPANEL_DIVIDER_LOCATION_2 = WorkbenchFrame.class.getName() + " - STATUSPANEL_DIVIDER_LOCATION_2";
public final static String STATUSPANEL_DIVIDER_LOCATION_3 = WorkbenchFrame.class.getName() + " - STATUSPANEL_DIVIDER_LOCATION_3";
public final static String STATUSPANEL_DIVIDER_LOCATION_4 = WorkbenchFrame.class.getName() + " - STATUSPANEL_DIVIDER_LOCATION_4";
public void saveWindowState() {
boolean maximized = (this.getExtendedState() == MAXIMIZED_BOTH);
Blackboard blackboard = PersistentBlackboardPlugIn.get(workbenchContext);
blackboard.put(MAXIMIZED_KEY, maximized);
Point p = this.getLocation(null);
blackboard.put(HORIZONTAL_KEY, p.x);
blackboard.put(VERTICAL_KEY, p.y);
Dimension d = this.getSize();
blackboard.put(WIDTH_KEY, d.width);
blackboard.put(HEIGHT_KEY, d.height);
// save the statuspanel divider locations
blackboard.put(STATUSPANEL_DIVIDER_LOCATION_1, new Integer(statusPanelSplitPane1.getLastDividerLocation()));
blackboard.put(STATUSPANEL_DIVIDER_LOCATION_2, new Integer(statusPanelSplitPane2.getLastDividerLocation()));
blackboard.put(STATUSPANEL_DIVIDER_LOCATION_3, new Integer(statusPanelSplitPane3.getLastDividerLocation()));
blackboard.put(STATUSPANEL_DIVIDER_LOCATION_4, new Integer(statusPanelSplitPane4.getLastDividerLocation()));
}
public boolean recallMaximizedState() {
Blackboard blackboard = PersistentBlackboardPlugIn.get(workbenchContext);
boolean maximized = false;
if (blackboard.get(MAXIMIZED_KEY) == null) {
blackboard.put(MAXIMIZED_KEY, maximized);
}
maximized = ((Boolean) blackboard.get(MAXIMIZED_KEY)).booleanValue();
return maximized;
}
public Point recallWindowLocation() {
Blackboard blackboard = PersistentBlackboardPlugIn.get(workbenchContext);
Point p = new Point(0,0);
if (blackboard.get(HORIZONTAL_KEY) == null) {
blackboard.put(HORIZONTAL_KEY, p.x);
blackboard.put(VERTICAL_KEY, p.y);
}
p.x = ((Integer) blackboard.get(HORIZONTAL_KEY)).intValue();
p.y = ((Integer) blackboard.get(VERTICAL_KEY)).intValue();
return p;
}
public Dimension recallWindowSize() {
Blackboard blackboard = PersistentBlackboardPlugIn.get(workbenchContext);
// restore Statusbar divider loactions
statusPanelSplitPane1.setDividerLocation(blackboard.get(STATUSPANEL_DIVIDER_LOCATION_1, 300));
statusPanelSplitPane2.setDividerLocation(blackboard.get(STATUSPANEL_DIVIDER_LOCATION_2, 200));
statusPanelSplitPane3.setDividerLocation(blackboard.get(STATUSPANEL_DIVIDER_LOCATION_3, 100));
statusPanelSplitPane4.setDividerLocation(blackboard.get(STATUSPANEL_DIVIDER_LOCATION_4, 200));
Dimension d = new Dimension(900, 665);
if (blackboard.get(WIDTH_KEY) == null) {
blackboard.put(WIDTH_KEY, d.width);
blackboard.put(HEIGHT_KEY, d.height);
}
d.width = ((Integer) blackboard.get(WIDTH_KEY)).intValue();
d.height = ((Integer) blackboard.get(HEIGHT_KEY)).intValue();
return d;
}
/**
* @return the taskListeners
*/
public ArrayList<TaskListener> getTaskListeners() {
return taskListeners;
}
/**
* Add's a TaskListener, wich will be fired if a Task was added
* via the WorkbenchFrame.addTaskFrame(TaskFrame taskFrame) or
* the a Task was loaded completly with all his layers.
*
* @param l - The TaskListener to add.
*/
public void addTaskListener(TaskListener l) {
getTaskListeners().add(l);
}
/**
* Remove's a TaskListener.
*
* @param l - The TaskListener to add.
*/
public void removeTaskListener(TaskListener l) {
getTaskListeners().remove(l);
}
}